package com.qqbot.impl.utils;

import com.qqbot.impl.exception.BException;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * MD5加密工具类
 *
 * @author changwenpeng
 * @date 2022年5月14日
 */
@Slf4j
public class SignMD5Utils {

    private static final String appId = "xxx";
    private static final String secret = "xxxxxxxx";

    public static void main(String[] args) throws IOException {
        long nowTimestamp = Instant.now().getEpochSecond();
        String updateTime = "2020/01/01 10:01:01";
        System.out.println();
        String timestamp = System.currentTimeMillis() / 1000 + "";
        // 时间戳要为10位的秒级时间戳
        if (timestamp.length() != 10) {
            throw new BException("timestamp时间戳格式错误");
        }
        ;
        String urlUpdateTime = updateTime.replaceAll(" ", "%20");
        //参数签名测试例子
        HashMap<String, String> signMap = new HashMap<>();
        signMap.put("appId", appId);
        signMap.put("timestamp", String.valueOf(nowTimestamp));
        signMap.put("updateTime", updateTime);
        String sign = getSign(signMap, secret);
        System.out.println("得到签名sign: " + sign);
        String url = "http://localhost:8081/open/api/xxxxxxxx?" + appId + "&timestamp=" + nowTimestamp +
                "&sign=" + sign + "&updateTime=" + urlUpdateTime;
        System.out.println("生成的url: " + url);
        //String resp = doGet(url);
        //System.out.println(resp);
    }

    /**
     * 得到签名
     *
     * @param params 参数集合,不含密钥secret
     * @param secret 分配的密钥secret
     * @return sign 签名
     */
    public static String getSign(Map<String, String> params, String secret) {
        StringBuilder sb = new StringBuilder();
        // 先对请求参数去重并排序
        Set<String> keySet = params.keySet();
        TreeSet<String> sortSet = new TreeSet<>(keySet);
        // 将排序后的参数与其对应值，组合成 参数=参数值 的格式，并且把这些参数用 & 字符连接起来，此时生成的字符串为待签名字符串
        for (String key : sortSet) {
            String value = params.get(key);
            sb.append(key).append("=").append(value).append("&");
        }
        sb.append("secret=").append(secret);
        byte[] md5Digest;
        // Md5加密得到sign
        md5Digest = getMd5Digest(sb.toString());
        return byte2hex(md5Digest);
    }

    /**
     * 获取md5信息摘要
     *
     * @param data 需要加密的字符串
     * @return bytes 字节数组
     */
    private static byte[] getMd5Digest(String data) {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data.getBytes(StandardCharsets.UTF_8));
        } catch (GeneralSecurityException gse) {
            log.error("生成签名错误", gse);
        }
        return bytes;
    }

    /**
     * 将字节数组转化为16进制
     *
     * @param bytes 字节数组
     * @return sign 签名
     */
    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (byte aByte : bytes) {
            String hex = Integer.toHexString(aByte & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }
}